<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div>
    <h2>一、是什么</h2>
    <div>继承可以使得子类具有父类别的各种属性和方法，而不需要再次编写相同的代码</div>
    <br>
    <div>在子类别继承父类别的同时，可以重新定义某些属性，并重写某些方法，即覆盖父类别的原有属性和方法，使其获得与父类别不同的功能</div>
  </div>
  <script>
    // 定义一个类（Class）叫汽车，汽车的属性包括颜色、轮胎、品牌、速度、排气量等
    // class Car{
    //   constructor(color,speed){
    //       this.color = color
    //       this.speed = speed
    //       // ...
    //   }
    // }
    // // 货车
    // class Truck extends Car{
    //     constructor(color,speed){
    //         super(color,speed)
    //         this.Container = true // 给货车添加一个大货箱
    //     }
    // }
    // class Truck extends Car{
    //     constructor(color,speed){
    //         super(color,speed)
    //         this.color = "black" //重写或覆盖某些属性和方法
    //         this.Container = true // 货箱
    //     }
    // }
  </script>
  <div>
    <h2>二、实现方式</h2>
    <div>
      <ul>
        <li>原型链继承</li>
        <li>构造函数继承（借助 call）</li>
        <li>组合继承</li>
        <li>原型式继承</li>
        <li>寄生式继承</li>
        <li>寄生组合式继承</li>
      </ul>
    </div>
  </div>
  <script>
    // 原型链继承
    // 缺点：实例化原型对象的属性是引用类型的时候，会出现浅拷贝，数据会互相收到影响
    // function Parent() {
    //   this.name = 'parent1';
    //   this.play = [1, 2, 3]
    // }
    // function Child() {
    //   this.type = 'child2';
    // }
    // 把Parent的实例对象挂载到子类的原型上，此时子类可以使用父类的属性和方法，
    // 但是子类的实例的原型改变，指向Parent
    // Child.prototype = new Parent();
    // let c1 = new Child()
    // s1.play.push(4) // 改变一个另一个也改变
    // let c2 = new Child()
    // console.log(c1,c2)


    // 构造函数继承
    // 构造函数的实例无法继承构造函数原型链的属性和方法
    // function Parent() {
    //   this.name = 'parent1';
    // }

    // Parent.prototype.getName = function () {
    //   return this.name;
    // }

    // function Child() {
    //   // call()的作用，调用该方法，并改变this指向
    //   Parent.call(this);
    //   this.type = 'child'// 此时child指向Parent
    // }

    // let child = new Child();
    // console.log(child);  // 没问题
    // // 重点 无法继承构造函数原型链的属性和方法
    // console.log(child.getName());  // 会报错


    // 组合式继承
    // function Parent() {
    //   this.name = 'parent1';
    //   this.play = [1, 2, 3]
    // }
    // function Child() {
    //   Parent.call(this) // 组合式继承
    //   this.type = 'child2';
    // }
    // Child.prototype = new Parent();
    // let c1 = new Child()
    // s1.play.push(4) // 改变一个另一个也改变
    // let c2 = new Child()
    // console.log(c1,c2)

    // 组合式继承优化
    function Parent() {
      this.name = 'parent1';
      this.play = [1, 2, 3]
    }
    function Child() {
      Parent.call(this) // 组合式继承
      this.type = 'child2';
    }
    // Child.prototype = Parent.prototype; // 让两个原型指向一个原型
    Child.prototype = Object.create(Parent.prototype); 
    console.log(Child.prototype.constructor);
    let c1 = new Child()
    c1.play.push(4) // 改变一个另一个也改变
    let c2 = new Child()
    console.log(c1,c2)
  </script>
</body>

</html>